﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using InterLinq.Client;
using InterLinq.Objects;
using InterLinq.Sebarf;
using InterLinq.Server.Services.Impl;
using InterLinq.Services.Interfaces;
using InterLinq.Test.DH;
using InterLinq.Test.PD;
using InterLinq.Views;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sebarf.Client;
using Sebarf.Configuration;
using Sebarf.Core;
using Sebarf.Core.Internal;
using Sebarf.ProcessChains.Interfaces;
using Sebarf.Profiles.WPF;
using Sebarf.Server;
using Sebarf.Services.Impl;
using Sebarf.Services.Interfaces;
using Sebastof.Server.Services.Impl;
using Sebastof.Services.Impl;
using Sebastof.Services.Interfaces;
using System.Security;

#endregion

namespace InterLinq.Test {
	/// <summary>
	/// This class tests the view stuff of InterLinq
	/// </summary>
	[TestClass]
	public class TestViews {
		#region Public Methods

		[TestMethod]
		public void RunSimpleView() {
			// create servicelocator
			var locator = new ServiceRegistrationLocatorService();

			// create products
			var product1 = new InterLinqProduct { Name = "Gugus1", AttachedServiceLocatorService = locator };
			var product2 = new InterLinqProduct { Name = "Gugus2", AttachedServiceLocatorService = locator };

			// create cache
			var cache = new SimpleCache();

			// register needed service
			locator.RegisterService(cache);

			// add data to cache
			cache.AddOrUpdateCachedValue(product1.Id, product1);
			cache.AddOrUpdateCachedValue(product2.Id, product2);

			// generate view
			var view = new GenericView { AttachedServiceLocatorService = locator };
			view.AddEntryFromDatasourceToView(product1, "Name as ProductName1");
			view.AddEntryFromDatasourceToView(product2, "Name as ProductName2");

			// create typed view
			var typedView = new ProductView(view);

			Assert.AreEqual("Gugus1", typedView.ProductName1);
			Assert.AreEqual("Gugus2", typedView.ProductName2);

			// modify view
			typedView.ProductName1 = "1";
			typedView.ProductName2 = "2";

			Assert.AreEqual("1", product1.Name);
			Assert.AreEqual("2", product2.Name);

			// simple conversation to typed view
			typedView = view.AsTypedView<ProductView>();
			Assert.AreEqual("1", typedView.ProductName1);
			Assert.AreEqual("2", typedView.ProductName2);
		}

		[TestMethod]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Application.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Application.xaml")]
		public void RunLinqBasedView() {
			// create sample data
			Dictionary<Type, IList> data = SampleDataFactory.CreateInterLinqOrdersWithContent(2, 10);

			// remeber the products on the server
			IQueryable<IProduct> serverProducts = ((List<IProduct>)data[typeof(IProduct)]).AsQueryable();

			// create server query handler
			var queryHandler = new ObjectQueryHandler(new ObjectBasedDataSource(data));

			// create server
			IServer server = WcfBasedServer.Create(delegate {
				// create the base service
				var locator = new ServiceRegistrationLocatorService();
				// register backend locator service
				locator.RegisterService(new BackendProviderService());
				// register query handler locator service
				locator.RegisterService(new QueryHandlerLocatorService { QueryHandler = queryHandler });
				// create engine
				RequestHandlerEngine toReturn = RequestHandlerEngine.Create(locator,
																			 RequestHandlerLoader
																				.Load(
																				"TestSampleApplication.RequestHandler.Server.Application.xaml"),
																			 RequestHandlerLoader
																				.Load(
																				"TestSampleApplication.RequestHandler.Server.Internal.xaml"));
				// add interlinq handler
				locator.GetRegisteredService<IAddRequestHandlerService>().
					AddAddionalHandler(new ExecuteLinqQueryRequestHandler { QueryHandler = queryHandler });
				// set backend provider
				locator.GetRegisteredService<IBackendProviderRegisterService>().
					SetBackendProvider(queryHandler);

				return toReturn;
			});

			try {
				// starts the interlinq server
				server.Start();

				// create client

				// create base service
				var clientServiceLocator = new ServiceRegistrationLocatorService();

				// create engine
				IClient client = WcfBasedClient.Create("Client 1",
														RequestHandlerEngine.Create(clientServiceLocator,
																					 RequestHandlerLoader.Load(
																						"TestSampleApplication.RequestHandler.Client.Internal.xaml")));

				// connect
				client.Connect();

				// load profiles
				client.Process(new WpfBasedProfileLoadRequest("Profile", "CacheBasedLazyLoadProfile_Server.xaml"));
				client.ProcessLocal(new WpfBasedProfileLoadRequest("Profile", "CacheBasedLazyLoadProfile.xaml"));

				// populate remote engine
				clientServiceLocator.GetRegisteredService<IRequestRemoteHandlerEngineLocatorService>().SetRemoteEngine(client);

				// create client datacontext
				var dataContext1 =
					new SampleDataContext(
						new InterLinqQueryHandler(
							new InterLinqQueryProvider(new SebarfBasedLinqQueryGateway(clientServiceLocator, client))));
				clientServiceLocator.RegisterService(new QueryHandlerLocatorService { QueryHandler = dataContext1.QueryHandler });

				// ensure dependencies
				client.Process(new ResolveServicesDependenciesRequest());
				client.Process(new ResolveProcessChainDependenciesRequest());
				client.ProcessLocal(new ResolveServicesDependenciesRequest());
				client.ProcessLocal(new ResolveProcessChainDependenciesRequest());

				// startup services
				client.Process(new SetupServicesRequest());
				client.ProcessLocal(new SetupServicesRequest());

				GenericView[] results =
					(from p in dataContext1.Products select new GenericView(new InternalData(p, new[] { "Name as ProductName" }))).
						ToArray();

				Assert.AreEqual(results[0].GetValue<String>("ProductName"), (data[typeof(IProduct)][0] as IProduct).Name);

				Assert.IsFalse(results[0].GetIsReadOnly("ProductName"));
				results[0].SetValue("ProductName", "Gugus");

				clientServiceLocator.GetRegisteredService<IChangeHandlerService>().SubmitChanges();

				Assert.AreEqual(dataContext1.Products.ToArray()[0].Name, "Gugus");

				// readonly, but faster view
				GenericView[] resultsReadOnly = (from p in dataContext1.Products
												 select
													new GenericView(new InternalData(p, new[] { "Name as ProductName" })).AsReadOnly())
					.ToArray();

				Assert.AreEqual(resultsReadOnly[0].GetValue<String>("ProductName"),
								 (data[typeof(IProduct)][0] as IProduct).Name);

				Assert.IsTrue(resultsReadOnly[0].GetIsReadOnly("ProductName"));

				bool isReadOnly = false;
				try {
					resultsReadOnly[0].SetValue("ProductName", "Gugus1");
				}
				catch (NotSupportedException) {
					isReadOnly = true;
				}
				Assert.IsTrue(isReadOnly);
			}
			finally {
				server.Stop();
			}
		}

		[TestMethod]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Application.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Application.xaml")]
		public void RunLinqBasedViewWithOrthogonalObjects() {
			// create sample data
			Dictionary<Type, IList> data = SampleDataFactory.CreateWPFOrdersWithContent(2, 10);

			// remeber the products on the server
			IQueryable<IProduct> serverProducts = ((List<IProduct>)data[typeof(IProduct)]).AsQueryable();

			// create server query handler
			var queryHandler = new ObjectQueryHandler(new ObjectBasedDataSource(data));

			// create server
			IServer server = WcfBasedServer.Create(delegate {
				// create the base service
				var locator = new ServiceRegistrationLocatorService();
				// register backend locator service
				locator.RegisterService(new BackendProviderService());
				// register query handler locator service
				locator.RegisterService(new QueryHandlerLocatorService { QueryHandler = queryHandler });
				// create engine
				RequestHandlerEngine toReturn = RequestHandlerEngine.Create(locator,
																			 RequestHandlerLoader
																				.Load(
																				"TestSampleApplication.RequestHandler.Server.Application.xaml"),
																			 RequestHandlerLoader
																				.Load(
																				"TestSampleApplication.RequestHandler.Server.Internal.xaml"));
				// add interlinq handler
				locator.GetRegisteredService<IAddRequestHandlerService>().
					AddAddionalHandler(new ExecuteLinqQueryRequestHandler { QueryHandler = queryHandler });
				// set backend provider
				locator.GetRegisteredService<IBackendProviderRegisterService>().
					SetBackendProvider(queryHandler);

				return toReturn;
			});

			try {
				// starts the interlinq server
				server.Start();

				// create client

				// create base service
				var clientServiceLocator = new ServiceRegistrationLocatorService();

				// create engine
				IClient client = WcfBasedClient.Create("Client 1",
														RequestHandlerEngine.Create(clientServiceLocator,
																					 RequestHandlerLoader.Load(
																						"TestSampleApplication.RequestHandler.Client.Internal.xaml")));

				// connect
				client.Connect();

				// load profiles
				client.Process(new WpfBasedProfileLoadRequest("Profile", "CacheBasedLazyLoadProfile_Server.xaml"));
				client.ProcessLocal(new WpfBasedProfileLoadRequest("Profile", "CacheBasedLazyLoadProfile.xaml"));

				// populate remote engine
				clientServiceLocator.GetRegisteredService<IRequestRemoteHandlerEngineLocatorService>().SetRemoteEngine(client);

				// create client datacontext
				var dataContext1 =
					new SampleDataContext(
						new InterLinqQueryHandler(
							new InterLinqQueryProvider(new SebarfBasedLinqQueryGateway(clientServiceLocator, client))));
				clientServiceLocator.RegisterService(new QueryHandlerLocatorService { QueryHandler = dataContext1.QueryHandler });

				// ensure dependencies
				client.Process(new ResolveServicesDependenciesRequest());
				client.Process(new ResolveProcessChainDependenciesRequest());
				client.ProcessLocal(new ResolveServicesDependenciesRequest());
				client.ProcessLocal(new ResolveProcessChainDependenciesRequest());

				// startup services
				client.Process(new SetupServicesRequest());
				client.ProcessLocal(new SetupServicesRequest());

				GenericView[] results =
					(from p in dataContext1.Products select new GenericView(new InternalData(p, new[] { "Name as ProductName" }))).
						ToArray();

				Assert.AreEqual(results[0].GetValue<String>("ProductName"), (data[typeof(IProduct)][0] as IProduct).Name);

				Assert.IsTrue(results[0].GetIsReadOnly("ProductName"));

				bool isReadOnly = false;
				try {
					results[0].SetValue("ProductName", "Gugus");
				}
				catch (NotSupportedException) {
					isReadOnly = true;
				}
				Assert.IsTrue(isReadOnly);
			}
			finally {
				server.Stop();
			}
		}

		[TestMethod]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Application.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Application.xaml")]
		public void RunLinqBasedViewWithComputedProperties() {
			// create sample data
			Dictionary<Type, IList> data = SampleDataFactory.CreateInterLinqOrdersWithContent(2, 10);

			// remeber the products on the server
			IQueryable<IProduct> serverProducts = ((List<IProduct>)data[typeof(IProduct)]).AsQueryable();

			// create server query handler
			var queryHandler = new ObjectQueryHandler(new ObjectBasedDataSource(data));

			// create server
			IServer server = WcfBasedServer.Create(delegate {
				// create the base service
				var locator = new ServiceRegistrationLocatorService();
				// register backend locator service
				locator.RegisterService(new BackendProviderService());
				// register query handler locator service
				locator.RegisterService(new QueryHandlerLocatorService { QueryHandler = queryHandler });
				// create engine
				RequestHandlerEngine toReturn = RequestHandlerEngine.Create(locator,
																			 RequestHandlerLoader
																				.Load(
																				"TestSampleApplication.RequestHandler.Server.Application.xaml"),
																			 RequestHandlerLoader
																				.Load(
																				"TestSampleApplication.RequestHandler.Server.Internal.xaml"));
				// add interlinq handler
				locator.GetRegisteredService<IAddRequestHandlerService>().
					AddAddionalHandler(new ExecuteLinqQueryRequestHandler { QueryHandler = queryHandler });
				// set backend provider
				locator.GetRegisteredService<IBackendProviderRegisterService>().
					SetBackendProvider(queryHandler);

				return toReturn;
			});

			try {
				// starts the interlinq server
				server.Start();

				// create client

				// create base service
				var clientServiceLocator = new ServiceRegistrationLocatorService();

				// create engine
				IClient client = WcfBasedClient.Create("Client 1",
														RequestHandlerEngine.Create(clientServiceLocator,
																					 RequestHandlerLoader.Load(
																						"TestSampleApplication.RequestHandler.Client.Internal.xaml")));

				// connect
				client.Connect();

				// load profiles
				client.Process(new WpfBasedProfileLoadRequest("Profile", "CacheBasedLazyLoadProfile_Server.xaml"));
				client.ProcessLocal(new WpfBasedProfileLoadRequest("Profile", "CacheBasedLazyLoadProfile.xaml"));

				// populate remote engine
				clientServiceLocator.GetRegisteredService<IRequestRemoteHandlerEngineLocatorService>().SetRemoteEngine(client);

				// create client datacontext
				var dataContext1 =
					new SampleDataContext(
						new InterLinqQueryHandler(
							new InterLinqQueryProvider(new SebarfBasedLinqQueryGateway(clientServiceLocator, client))));
				clientServiceLocator.RegisterService(new QueryHandlerLocatorService { QueryHandler = dataContext1.QueryHandler });

				// ensure dependencies
				client.Process(new ResolveServicesDependenciesRequest());
				client.Process(new ResolveProcessChainDependenciesRequest());
				client.ProcessLocal(new ResolveServicesDependenciesRequest());
				client.ProcessLocal(new ResolveProcessChainDependenciesRequest());

				// startup services
				client.Process(new SetupServicesRequest());
				client.ProcessLocal(new SetupServicesRequest());

				GenericView[] results =
					(from p in dataContext1.Products select new GenericView(new InternalData(p, new[] { "Name as ProductName" }))).
						ToArray();

				Assert.AreEqual(results[0].GetValue<String>("ProductName"), ((IProduct)data[typeof(IProduct)][0]).Name);

				Assert.IsFalse(results[0].GetIsReadOnly("ProductName"));
				results[0].SetValue("ProductName", "Gugus");

				clientServiceLocator.GetRegisteredService<IChangeHandlerService>().SubmitChanges();

				Assert.AreEqual(dataContext1.Products.ToArray()[0].Name, "Gugus");

				// view with updateable and readonly (computed properties)
				GenericView[] result = (from p in dataContext1.Products
										select
										   new GenericView(new InternalData(p, new[] { "Name as ProductName" })).AddEntryToView("NameUpper", p.Name.ToUpper()))
					.ToArray();

				Assert.AreEqual(result[0].GetValue<String>("ProductName"),
								 ((IProduct)data[typeof(IProduct)][0]).Name);

				Assert.AreEqual(result[0].GetValue<String>("NameUpper"),
								 ((IProduct)data[typeof(IProduct)][0]).Name.ToUpper());


				Assert.IsFalse(result[0].GetIsReadOnly("ProductName"));
				Assert.IsTrue(result[0].GetIsReadOnly("NameUpper"));

				var exThrow = false;
				try {
					result[0].SetValue("NameUpper", "huhu");
				}
				catch (NotSupportedException) {
					exThrow = true;
				}
				finally {
					Assert.IsTrue(exThrow);
				}

				exThrow = false;
				try {
					result[0].SetValue("ProductName", "huhu2");
				}
				catch (NotSupportedException) {
					exThrow = true;
				}
				finally {
					Assert.IsFalse(exThrow);
				}
			}
			finally {
				server.Stop();
			}
		}


		[TestMethod]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Application.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Application.xaml")]
		public void RunPendingChangesWhileLoadingAnObject() {
			// create sample data
			Dictionary<Type, IList> data = SampleDataFactory.CreateInterLinqOrdersWithContent(2, 10);

			// remeber the products on the server
			IQueryable<IProduct> serverProducts = ((List<IProduct>)data[typeof(IProduct)]).AsQueryable();

			// create server query handler
			var queryHandler = new ObjectQueryHandler(new ObjectBasedDataSource(data));

			// create server
			IServer server = WcfBasedServer.Create(delegate {
				// create the base service
				var locator = new ServiceRegistrationLocatorService();
				// register backend locator service
				locator.RegisterService(new BackendProviderService());
				// register query handler locator service
				locator.RegisterService(new QueryHandlerLocatorService { QueryHandler = queryHandler });
				// create engine
				RequestHandlerEngine toReturn = RequestHandlerEngine.Create(locator,
																			 RequestHandlerLoader
																				.Load(
																				"TestSampleApplication.RequestHandler.Server.Application.xaml"),
																			 RequestHandlerLoader
																				.Load(
																				"TestSampleApplication.RequestHandler.Server.Internal.xaml"));
				// add interlinq handler
				locator.GetRegisteredService<IAddRequestHandlerService>().
					AddAddionalHandler(new ExecuteLinqQueryRequestHandler { QueryHandler = queryHandler });
				// set backend provider
				locator.GetRegisteredService<IBackendProviderRegisterService>().
					SetBackendProvider(queryHandler);

				return toReturn;
			});

			try {
				// starts the interlinq server
				server.Start();

				// create client

				// create base service
				var clientServiceLocator = new ServiceRegistrationLocatorService();

				// create engine
				IClient client = WcfBasedClient.Create("Client 1",
														RequestHandlerEngine.Create(clientServiceLocator,
																					 RequestHandlerLoader.Load(
																						"TestSampleApplication.RequestHandler.Client.Internal.xaml")));
				// connect
				client.Connect();

				// load profiles
				client.Process(new WpfBasedProfileLoadRequest("Profile", "CacheBasedLazyLoadProfile_Server.xaml"));
				client.ProcessLocal(new WpfBasedProfileLoadRequest("Profile", "CacheBasedLazyLoadProfile.xaml"));

				// populate remote engine
				clientServiceLocator.GetRegisteredService<IRequestRemoteHandlerEngineLocatorService>().SetRemoteEngine(client);

				// create client datacontext
				var dataContext1 =
					new SampleDataContext(
						new InterLinqQueryHandler(
							new InterLinqQueryProvider(new SebarfBasedLinqQueryGateway(clientServiceLocator, client))));
				clientServiceLocator.RegisterService(new QueryHandlerLocatorService { QueryHandler = dataContext1.QueryHandler });

				// ensure dependencies
				client.Process(new ResolveServicesDependenciesRequest());
				client.Process(new ResolveProcessChainDependenciesRequest());
				client.ProcessLocal(new ResolveServicesDependenciesRequest());
				client.ProcessLocal(new ResolveProcessChainDependenciesRequest());

				// startup services
				client.Process(new SetupServicesRequest());
				client.ProcessLocal(new SetupServicesRequest());

				// add a change without a ref to the object
				clientServiceLocator.GetRegisteredService<IAppliedChangesOnObjectsCollectorService>().
					DepositeValueChangedByObjectIdEntry("Name", "Gugus", (data[typeof(IProduct)][0] as IProduct).Id.ToString(),
														 (data[typeof(IProduct)][0]).GetType(),
														 ((IVersionedObject)data[typeof(IProduct)][0]).GetVersion());

				// load object
				IProduct results = (from p in dataContext1.Products select p).ToArray()[0];

				// should store the pending value
				Assert.AreEqual(results.Name, "Gugus");
			}
			finally {
				server.Stop();
			}
		}

		private class ProductView : TypedView {
			public ProductView(GenericView view)
				: base(view) {
			}

			public ProductView() {
			}

			public string ProductName1 {
				get { return GetValue<String>("ProductName1"); }
				set { SetValue("ProductName1", value); }
			}

			public string ProductName2 {
				get { return GetValue<String>("ProductName2"); }
				set { SetValue("ProductName2", value); }
			}
		}

		#endregion
	}
}